package com.aide.security.encoding;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author 作者 : sorc
 * @version 创建时间：2012-11-12 下午4:25:32
 * 
 *          类说明
 */
public class Base64 {
	public static String StringToBase64(String data) {
		return ByteToBase64(data.getBytes());
	}

	public static String FileToBase64(String path) {
		return FileToBase64(new File(path));
	}

	public static boolean Base64ToFile(File file, String data) {
		FileOutputStream fos = null;
		try {
			byte[] result = Base64.Base64ToByte(data);
			File pf = file.getParentFile();
			if (!pf.exists() || !pf.isDirectory()) {
				pf.mkdirs();
			}
			if (file.exists() && file.isFile()) {
				file.delete();
			}
			fos = new FileOutputStream(file);
			fos.write(result);
			fos.flush();
			fos.close();
			return true;
		} catch (Exception e) {
			System.out.println("文件："+file.getPath());
			System.out.println(data);
			e.printStackTrace();
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
				}
			}
		}
		return false;
	}

	public static String FileToBase64(File file) {
		String result = "";
		FileInputStream fis = null;
		BufferedInputStream in = null;
		ByteArrayOutputStream out = null;
		int buffsize = 1024;
		if (file.length() > 1024 * 1024 * 100) {
			buffsize = 1024 * 1024;
		}
		if (file.length() > 1024 * 1024 * 1024) {
			buffsize = 1024 * 1024 * 10;
		}
		try {
			fis = new FileInputStream(file);
			in = new BufferedInputStream(fis);
			out = new ByteArrayOutputStream(buffsize);
			byte[] temp = new byte[buffsize];
			int tempsize = 0;
			while ((tempsize = in.read(temp)) != -1) {
				out.write(temp, 0, tempsize);
			}
			byte[] content = out.toByteArray();
			result = Base64.ByteToBase64(content);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (fis != null)
					fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (in != null)
					in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

			System.out.println("关闭文件流");
		}
		return result;
	}

	/**
	 * 将原始数据编码为base64编码
	 */
	public static String ByteToBase64(byte[] data) {
		char[] out = new char[((data.length + 2) / 3) * 4];
		for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
			boolean quad = false;
			boolean trip = false;
			int val = (0xFF & (int) data[i]);
			val <<= 8;
			if ((i + 1) < data.length) {
				val |= (0xFF & (int) data[i + 1]);
				trip = true;
			}
			val <<= 8;
			if ((i + 2) < data.length) {
				val |= (0xFF & (int) data[i + 2]);
				quad = true;
			}
			out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
			val >>= 6;
			out[index + 1] = alphabet[val & 0x3F];
			val >>= 6;
			out[index + 0] = alphabet[val & 0x3F];
		}
		return new String(out);
	}

	public static String Base64ToString(String str) throws Exception {
		return new String(Base64ToByte(str));
	}

	/**
	 * 将base64编码的数据解码成原始数据
	 * 
	 * @throws Exception
	 */
	public static byte[] Base64ToByte(String str) throws Exception {
		char[] data = str.toCharArray();
		int len = ((data.length + 3) / 4) * 3;
		if (data.length > 0 && data[data.length - 1] == '=')
			--len;
		if (data.length > 1 && data[data.length - 2] == '=')
			--len;
		byte[] out = new byte[len];
		int shift = 0;
		int accum = 0;
		int index = 0;
		for (int ix = 0; ix < data.length; ix++) {
			int value = codes[data[ix] & 0xFF];
			if (value >= 0) {
				accum <<= 6;
				shift += 6;
				accum |= value;
				if (shift >= 8) {
					shift -= 8;
					out[index++] = (byte) ((accum >> shift) & 0xff);
				}
			}
		}
		if (index != out.length)
			throw new Exception("miscalculated data length!");
		return out;
	}

	static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
			.toCharArray();
	static private byte[] codes = new byte[256];
	
	static {
		for (int i = 0; i < 256; i++)
			codes[i] = -1;
		for (int i = 'A'; i <= 'Z'; i++)
			codes[i] = (byte) (i - 'A');
		for (int i = 'a'; i <= 'z'; i++)
			codes[i] = (byte) (26 + i - 'a');
		for (int i = '0'; i <= '9'; i++)
			codes[i] = (byte) (52 + i - '0');
		codes['+'] = 62;
		codes['/'] = 63;
	} 
}
